package com.joonhat.MonkeyFlash;

import java.io.IOException;

import javax.microedition.amms.control.camera.FlashControl;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.control.VideoControl;

import net.rim.device.api.system.Backlight;
import net.rim.device.api.system.LED;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.UiApplication;


/**
 * 	VideoField를 Manager.sublayout 에서 지정해주지 않으면 비디오가 화면에 뜨지 않음
 *  Player.stop이나 FlashControl.mode(off)등을 쓰면 에러가 속출하는데
 *  VideoField를 add/delete 하면 에러없이 작동을 잘함
 */
class SimpleFlash {

	private static final SimpleFlash simpleFlash = new SimpleFlash();
	
	private static Field videoField;
	private static Manager manager;
	private static Thread simpleFlashThread;
	
	private SimpleFlash() {
		Player videoPlayer = null;
		try {
			videoPlayer = javax.microedition.media.Manager
					.createPlayer("capture://video?encoding=video/3gpp");
			videoPlayer.realize();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (MediaException e) {
			e.printStackTrace();
		}
		VideoControl videoCtrl = (VideoControl) videoPlayer
				.getControl("javax.microedition.media.control.VideoControl");
		FlashControl flashCtrl = (FlashControl) videoPlayer
				.getControl("javax.microedition.amms.control.camera.FlashControl");
		videoField = (Field) videoCtrl.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, 
				"net.rim.device.api.ui.Field");
		flashCtrl.setMode(FlashControl.FORCE);

		try {
			videoPlayer.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static SimpleFlash getIns(){
		return simpleFlash;
	}
	
	public static void setManager(Manager manager){
		SimpleFlash.manager = manager;
	}
	
	public static Field getVideoField() {
		return videoField;
	}

	public static synchronized void startSimpleFlash() {
		if (videoField.getIndex()>=0) return;
		simpleFlashThread = new Thread(){
			public void run() {
				try {
					addVideoField();
					sleep(Integer.MAX_VALUE);
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally{
					treatmentStopFlash();
				}
			}

			private void treatmentStopFlash() {
				delVideoField();
			}
		};
		simpleFlashThread.start();
	}
	
	public static synchronized void stopSimpleFlash(){
		if (simpleFlashThread == null || simpleFlashThread.isAlive() == false) return;
		simpleFlashThread.interrupt();
	}
	
	private static synchronized void addVideoField() {
		if (videoField.getIndex()!=-1) return;
		synchronized (UiApplication.getEventLock()) {
			manager.add(videoField);
		}
	}
	
	private static synchronized void delVideoField() {
		if (videoField.getIndex()==-1) return;
		synchronized (UiApplication.getEventLock()) {
			manager.delete(videoField);
		}
	}
}


class FlashTimer extends Observable implements Observer {
	
	private static final FlashTimer flashTimer = new FlashTimer();
	private static SimpleOption simpleOption;
	private static StartTimer startTimer = new StartTimer();
	private boolean optionChange;
	
	private FlashTimer() {
		simpleOption = SimpleOption.getIns();
		simpleOption.addObserver(this);
	}
	
	public static FlashTimer getIns(){
		return flashTimer;
	}
	
	public void stopAndStart() {
		StartTimer.stop();
		startTimer.start(this);
	}
	
	public void stop(){
		startTimer.stop();
	}

	public String getRemainingTime() {
		return startTimer.getRemainingTime();
	}
	
	public boolean isOptionChange() {
		return optionChange;
	}

	public void setOptionChange(boolean optionChange) {
		this.optionChange = optionChange;
	}
	
	public void update(Observable observable) {
		setOptionChange(true);
		stopAndStart();
	}
}

class StartTimer {
	
	private static Thread thread;
	private static Object lock = new Object();
	private static Option option = Option.getIns();
	private static SimpleFlash simpleFlash = SimpleFlash.getIns();
	private static SimpleOption simpleOption = SimpleOption.getIns();
	private static String remainingTime;
	
	public void start(final FlashTimer flashTimer){
		
		thread = new Thread() {
			public synchronized void run() {
				synchronized (lock) {
					try {
						exeList();
						workSeconds();
						completeMesage();
					} catch (InterruptedException e) {
						e.printStackTrace();
						interruptMessage();
					} finally {
						closeList();
						falseFlags(flashTimer);
					}
				}
			}

			private void falseFlags(final FlashTimer flashTimer) {
				flashTimer.setOptionChange(false);
				simpleOption.setToggleFlash(false);
			}
			
			private void interruptMessage() {
				remainingTime = "";
				flashTimer.notifyObservers();
			}
			
			private void completeMesage() {
				remainingTime = "작동종료";
				flashTimer.notifyObservers();
			}
			
			private void workSeconds() throws InterruptedException {
				int second = getSecond();
				for (int i = 0; i < second; i++) {
					if (timerStopSituation()) break;
					flashTimer.notifyObservers();
					subRemainingTime();
					sleep(1000);
				}
			}
			
			private void subRemainingTime(){
				remainingTime = String.valueOf(Integer.parseInt(remainingTime)-1);
			}
			
			private int getSecond(){
				int second = getDuration() / 1000;
				remainingTime = String.valueOf(second);
				return second;
			}
			
			private boolean timerStopSituation() {
				return (option.getLastMode() == Option.SIMPLE_MODE == false ||
						ScreenCtrl.getIns().isMyScreenDisplayed() == false);
			}
			
			private void exeList(){
				Backlight.enable(true, Integer.MAX_VALUE);
				determineFlashOn();
				determineLedOn();
			}
			
			private void closeList(){
				determineFlashOff();
				determineLedOff();
				Backlight.setTimeout(Backlight.getTimeoutDefault());
			}

			private void determineLedOff() {
				if (simpleOption.isToggleFlash()) return;
				LED.setState(LED.STATE_OFF);
			}

			private void determineFlashOff() {
				if (flashTimer.isOptionChange()) return;
				SimpleFlash.stopSimpleFlash();
			}
			
			private void determineFlashOn() {
				if (simpleOption.isCurrentFlashOn() == false) return;
				SimpleFlash.startSimpleFlash();
			}
			
			private void determineLedOn() {
				if (simpleOption.isLed() == false) return;
				LED.setColorConfiguration(100, 0, Color.WHITE);
			}
		};
		thread.start();
	}
	
	public String getRemainingTime(){
		return StartTimer.remainingTime;
	}

	public static synchronized void stop() {
		if (thread == null || thread.isAlive() == false) return;
		thread.interrupt();
	}

	private static int getDuration(){
		return Integer.parseInt(SimpleOption.getIns().getDuration());
	}
}
